package game;

import enums.Directions;
import enums.PlayerSigns;
import exceptions.InvalidLineIndexingException;
import exceptions.NoSuchDirectionException;
import interfaces.IHandler;

/**
 * Class, representing the MVC handler for the game, has a background game board
 * matrix, on which the logic is done
 * 
 * @author Home
 * 
 */
public class GameHandler implements IHandler {

	private String[][] gameBoard;
	private int boardSize;
	private int emptyCellsCount;

	public GameHandler(int boardSize) {

		setBoardSize((2 * boardSize) + 1);
		gameBoard = new String[this.boardSize][this.boardSize];
		initializeGameBoard();
		emptyCellsCount = (int) Math.pow(boardSize, 2);

	}

	@Override
	public int getRowsCount() {
		return boardSize;
	}

	@Override
	public int getColsCount() {
		return boardSize;
	}

	@Override
	public String getStringForRowAndCol(int row, int col) {

		return String.valueOf(gameBoard[row][col]);

	}

	/**
	 * Fills a line in the matrix
	 * 
	 * @param line
	 *            - the line which the player selected for drawing
	 * @return whether the player has scored a point or not
	 * @throws InvalidLineIndexingException
	 */
	public boolean updateGameBoard(Line line, String/* PlayerSigns */sign)
			throws InvalidLineIndexingException {

		String verticalLine = "|";
		String horizontalLine = "-";

		int row = (line.getRow() * 2);
		int col = (line.getCol() * 2);

		try {
			if (line.getDirection().equals(Directions.U)) {
				row -= 1;
				checkForDuplicateLine(verticalLine, row, col);
			} else if (line.getDirection().equals(Directions.D)) {
				row += 1;
				checkForDuplicateLine(verticalLine, row, col);
			} else if (line.getDirection().equals(Directions.R)) {
				col += 1;
				checkForDuplicateLine(horizontalLine, row, col);
			} else {
				col -= 1;
				checkForDuplicateLine(horizontalLine, row, col);
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InvalidLineIndexingException("Invalid index.");
		}

		return hasScored(row, col, sign);

	}

	private void checkForDuplicateLine(String line, int row, int col)
			throws InvalidLineIndexingException {
		if (gameBoard[row][col] == " ") {
			gameBoard[row][col] = line;
		} else {
			throw new InvalidLineIndexingException(
					"This cell is already taken.");
		}
	}

	/*
	 * determines if the player has scored after filling line, and if so, fills
	 * the players sign in the array
	 */
	private boolean hasScored(int row, int col, String /* PlayerSigns */sign) {
		int flag = emptyCellsCount;
		/*
		 * if player has filed horizontal line
		 */
		if (row % 2 == 0 /*&& col % 2 != 0*/) {
			
			//check if there is up cell
			if (row > 0) {

				if (!gameBoard[row - 2][col].equals(" ")
						&& !gameBoard[row - 1][col - 1].equals(" ")
						&& !gameBoard[row - 1][col + 1].equals(" ")) {

					// fill player sign
					gameBoard[row - 1][col] = sign;
					emptyCellsCount--;
				}
			}

			// check if there is down cell
			if (row < boardSize - 1) {

				if (!gameBoard[row + 2][col].equals(" ")
						&& !gameBoard[row + 1][col - 1].equals("")
						&& !gameBoard[row + 1][col + 1].equals("")) {

					// fill player sign
					gameBoard[row + 1][col] = sign;
					emptyCellsCount--;
				}
			}

		}

		/*
		 * player has filled vertical line
		 */
		else {

			//check if there is left cell
			if (col > 0) {
				if (!gameBoard[row - 1][col - 1].equals(" ")
						&& !gameBoard[row][col - 2].equals(" ")
						&& !gameBoard[row + 1][col - 1].equals(" ")) {

					// fill player sign
					gameBoard[row][col - 1] = sign;
					emptyCellsCount--;
				}
			}

			//check if there is right cell
			if (col < boardSize - 1) {
				if (!gameBoard[row - 1][col + 1].equals(" ")
						&& !gameBoard[row][col + 2].equals(" ")
						&& !gameBoard[row + 1][col + 1].equals(" ")) {

					// fill player sign
					gameBoard[row][col + 1] = sign;
					emptyCellsCount--;
				}
			}
		}

		return (flag == emptyCellsCount) ? false : true;
	}

	/*
	 * initializes the initial state of the gameBoard field
	 */
	private void initializeGameBoard() {
		String point = ".";
		String space = " ";

		for (int i = 0; i < this.getRowsCount(); i++) {
			for (int j = 0; j < this.getColsCount(); j++) {
				if (i % 2 == 0 && j % 2 == 0) {
					this.gameBoard[i][j] = point;
				} else {
					this.gameBoard[i][j] = space;
				}
			}
		}
	}

	/*
	 * validates and then sets the value of boardSize field
	 */
	private void setBoardSize(int boardSize) {

		if (boardSize > 0) {
			this.boardSize = boardSize;
		}

	}

	/**
	 * 
	 * @return empty cells count on the game board
	 */
	public int getEmptyCellsCount() {
		return emptyCellsCount;
	}

}
